package com.yuma.tingshu.user.service.impl;

import com.alibaba.fastjson.JSON;
import com.yuma.tingshu.common.constant.RabbitConstant;
import com.yuma.tingshu.common.constant.RedisConstant;
import com.yuma.tingshu.common.constant.SystemConstant;
import com.yuma.tingshu.common.util.AuthContextHolder;
import com.yuma.tingshu.common.util.MongoUtil;
import com.yuma.tingshu.model.user.UserListenProcess;
import com.yuma.tingshu.user.service.UserListenProcessService;
import com.yuma.tingshu.vo.album.TrackStatMqVo;
import com.yuma.tingshu.vo.user.UserListenProcessVo;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class UserListenProcessServiceImpl implements UserListenProcessService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public BigDecimal getTrackBreakSecond(Long trackId) {
        // 判断参数
        if (trackId == null)
            return BigDecimal.ZERO;

        // 获取登录状态
        Long userId = AuthContextHolder.getUserId();
        if (userId == null) {
            return BigDecimal.ZERO;
        }

        // 计算当前用户的播放进度在那个集合中
        String collectionName = MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId);
        // 根据userId和声音id查询播放进度
        UserListenProcess userListenProcess = this.mongoTemplate.findOne(
                Query.query(Criteria.where("userId").is(userId).and("trackId").is(trackId)),
                UserListenProcess.class,
                collectionName
        );

        if (userListenProcess == null) {
            return BigDecimal.ZERO;
        }

        return userListenProcess.getBreakSecond();
    }

    //@Override
    public void updateListenProcess(UserListenProcessVo userListenProcessVo) {
        // 1.得到用户ID，如果没有登录，直接返回
        Long userId = AuthContextHolder.getUserId();
        if (userId == null) {
            return;
        }
        Long trackId = userListenProcessVo.getTrackId();
        // 2.根据MongoDB拿到声音集合名字
        String collectionName = MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId);
        // 3.根据userId和声音id查询播放进度
        UserListenProcess userListenProcess = this.mongoTemplate.findOne(
                Query.query(Criteria.where("userId").is(userId).and("trackId").is(trackId)),
                UserListenProcess.class,
                collectionName);
        // 4.判断播放进度，如果没有，则新增播放进度，否则更新播放进度
        if (userListenProcess == null) {
            // 新增播放进度
            userListenProcess = new UserListenProcess();
            BeanUtils.copyProperties(userListenProcessVo, userListenProcess);
            userListenProcess.setId(IdWorker.getIdStr());
            userListenProcess.setUserId(userId);
            userListenProcess.setIsShow(1);
            userListenProcess.setCreateTime(new Date());
            userListenProcess.setUpdateTime(userListenProcess.getCreateTime());
        } else {
            // 更新播放进度
            userListenProcess.setBreakSecond(userListenProcessVo.getBreakSecond());
            userListenProcess.setUpdateTime(new Date());
        }
        // 更新或者新增
        this.mongoTemplate.save(userListenProcess, collectionName);

        // 验证四个一：同一个用户同一个声音同一天只统计一次(幂等性)
        String key = RedisConstant.USER_LISTEN_PROCESS_PREFIX + userId;
        Boolean bit = this.redisTemplate.opsForValue().getBit(key, trackId);
        if (bit) {
            return;
        }
        // 如果没有统计过则进行统计，首先先标记为已统计，并且设置过期时间是第二天凌晨
        this.redisTemplate.opsForValue().setBit(key, trackId, true);
        this.redisTemplate.expire(key, this.getExpireTime(), TimeUnit.MILLISECONDS);

        // 发送消息给RabbitMQ进行播放量的统计
        TrackStatMqVo statMqVo = new TrackStatMqVo();
        statMqVo.setBusinessNo(IdWorker.getIdStr()); // 防重复消费的唯一标识
        statMqVo.setAlbumId(userListenProcessVo.getAlbumId());
        statMqVo.setTrackId(userListenProcessVo.getTrackId());
        statMqVo.setStatType(SystemConstant.TRACK_STAT_PLAY);
        statMqVo.setCount(1);
        this.rabbitTemplate.convertAndSend(RabbitConstant.ALBUM_EXCHANGE, RabbitConstant.PLAY_STAT_RK, JSON.toJSONString(statMqVo));
    }

    // 获取播放进度的过期时间，默认是第二天凌晨
    private long getExpireTime() {
        LocalDateTime endTime = LocalDateTime.of(LocalDate.now().plusDays(1), LocalTime.MIN);
        return ChronoUnit.MILLIS.between(LocalDateTime.now(), endTime);
    }

    @Override
    public Map<String, Long> getLatelyTrack() {

        Map<String, Long> map = new HashMap<>();
        // 1.获取登录用户
        Long userId = AuthContextHolder.getUserId();
        // 2.如果没登录，返回TrackId, AlbumId(推荐最火的声音进行播放，广告位)设置给Map
        if(userId == null){
            map.put("trackId", 51949L);
            map.put("albumId", 1603L);
            return map;
        }
        // 3.如果登录，则查询mongoDB把返回的对象封装到UserListenProcess中
        String collectionName = MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId);
        UserListenProcess userListenProcess = this.mongoTemplate.findOne(
                Query.query(Criteria.where("userId").is(userId))
                        .with(Sort.by(Sort.Order.desc("updateTime")))
                        .limit(1),
                UserListenProcess.class,
                collectionName
        );
        // 4.判断，如果为空，同2
        if(userListenProcess == null){
            map.put("trackId", 51949L);
            map.put("albumId", 1603L);
            return map;
        }
        // 5.不为空，从UserListenProcess中获取TrackId和AlbumId设置给Map
        map.put("trackId", userListenProcess.getTrackId());
        map.put("albumId", userListenProcess.getAlbumId());
        // 6.返回Map
        return map;
    }
}
